%{
#define YYDEBUG 1
#include <ctype.h>
#include <stdio.h>

#include "tabela.c"
#include "tradutor.c"
#define YYSTYPE no

int linha = 1;


void yyerror(const char *str) {
        fprintf(stderr,"line: %d\nerror: %s\n",linha, str);
}

%}

%start program

%token IF
%token THEN
%token ELSE
%token ID
%token NUMERO
%token RELOP 
%token FLOAT
%token VAR 
%token CONST 
%token TYPE 
%token PROGRAM 
%token INICIO 
%token FIM 
%token FOR     
%token WHILE 
%token DO 
%token TO 
%token DOWNTO 
%token REPEAT 
%token UNTIL 
%token CASE 
%token FUNCTION 
%token PROCEDURE 
%token ASPECT 
%token BEFORE 
%token AFTER 
%token RECORD 
%token ARRAY 
%token RANGE 
%token TRUE 
%token FALSE 
%token BOOLEAN 
%token REAL 
%token INTEGER 
%token STRING_TYPE 
%token CHAR_TYPE 
%token STRING_TERM 
%token CHAR_TERM 
%token POINTER
%token OP_ARITMETICO 
%token ATRIBUICAO 
%token DOISPONTOS 
%token PONTO 
%token PONTOEVIRGULA 
%token ABRECOL 
%token FECHACOL 
%token ABREPAR 
%token FECHAPAR 
%token CONST_ATRIB
%token MAIS 
%token MENOS 
%token NAO 
%token OP_LOGICO 
%token OF

%left OP_LOGICO
%left MAIS MENOS
%left OP_ARITMETICO



%%

literal : CHAR_TERM {$$ = $1}
        | NUMERO {$$ = $1}
        | STRING_TERM {$$ = $1}
        | FLOAT  {$$ = $1}
        ;

id_rule : ID {$$ = $1;}
        ;

program        : PROGRAM id_rule PONTOEVIRGULA program_body  PONTO {
       
                                                                no * nos = (no*)malloc(sizeof(no));
                                                                nos[0] = $4;    
                                                                $$ = criarNovoNo(NULL,0,1,nos);
                                                                printOnFile($$);
                                                                printf("\nCompilado!\n");
                                                             }
        ;

program_body     : const_section {$$ = $1}
        ;
    
const_section     : const_decl PONTOEVIRGULA type_section {
                                                               no* nos = (no*)malloc(2*sizeof(no));
                                                               nos[0] = $1;
                                                               nos[1] = $3;    
                                                               $$ = criarNovoNo(NULL,0,2,nos);                            
                                                          }
        | type_section {$$ = $1}
        ;

type_section     : type_decl PONTOEVIRGULA var_section {
                                                               no* nos = (no*)malloc(2*sizeof(no));
                                                               nos[0] = $1;
                                                               nos[1] = $3;    
                                                               $$ = criarNovoNo(NULL,0,2,nos);                            
                                                       }
        | var_section {$$ = $1}  
        ;
    
var_section     : var_decl PONTOEVIRGULA proc_fun_section {
                                                               no* nos = (no*)malloc(2*sizeof(no));
                                                               nos[0] = $1;
                                                               nos[1] = $3;    
                                                               $$ = criarNovoNo(NULL,0,2,nos);                            
                                                          }
        | proc_fun_section {$$ = $1}
        ;
    
proc_fun_section: proc_fun_decl PONTOEVIRGULA aspect_section {
                                                               no* nos = (no*)malloc(2*sizeof(no));
                                                               nos[0] = $1;
                                                               nos[1] = $3;    
                                                               $$ = criarNovoNo(NULL,0,2,nos);                            
                                                             }
        | aspect_section {$$ = $1}
        ;

aspect_section    : aspect_decl PONTOEVIRGULA before_after_list PONTOEVIRGULA entra_bloco_principal {
                                                                                                       no* nos = (no*)malloc(3*sizeof(no));
                                                                                                       nos[0] = $1;
                                                                                                       nos[1] = $3;    
                                                                                                       nos[2] = $5;
                                                                                                       $$ = criarNovoNo (NULL,0,3,nos);
                                                                                                    }



        | entra_bloco_principal {$$ = $1}
        ;

entra_bloco_principal : bloco {
                                   no* nos = (no*)malloc(sizeof(no));
                                   nos[0] = $1;
                                   $$ = criarNovoNo("int main()\n",1,1,nos);                            
                              }
                      ;

const_decl : CONST id_rule CONST_ATRIB literal {
                                                int retorno = inserirConstante($2.stringValue,$4.stringValue,$4.tipo,1);



                                                if(retorno == ERR_CONSTANTE_EXISTE)      
                                                {
                                                   yyerror("\nJa existe constante com esse nom\n ");
                                                   exit(1);
                                                }                                                

                                                char tipoNome[strlen($2.stringValue) + strlen($4.stringValue)];
                                                strcpy(tipoNome,"const ");

                                                if(FLOAT_V == $4.tipo) strcat(tipoNome,"float ");
                                                else if(INT_V == $4.tipo) strcat(tipoNome,"int ");
                                                else if(CHAR_V == $4.tipo) strcat(tipoNome, "char ");
                                                else if(STRING_V == $4.tipo) strcat(tipoNome, "char* ");

                                                strcat(tipoNome,$2.stringValue);

                                                strcat(tipoNome," = ");

                                                strcat(tipoNome,$4.stringValue);
                                                strcat(tipoNome,";\n");
            
                                                $$ = criarNovoNo(tipoNome,1,0,NULL);
                                                printf("%s",tipoNome);
                                                
                                          }

           | const_decl PONTOEVIRGULA ID CONST_ATRIB literal 
           ;
    
type_decl  : TYPE ID CONST_ATRIB type_st
       | type_decl PONTOEVIRGULA ID CONST_ATRIB type_st
       ;
 
var_decl       : VAR ID DOISPONTOS tipo
        | var_decl PONTOEVIRGULA ID DOISPONTOS tipo
        ;

proc_fun_decl    : proc_fun_decl  PROCEDURE procedure
        | proc_fun_decl  FUNCTION function
        |
        ;

procedure    : proc_or_func1 proc_or_func2
        ;

function    : proc_or_func1 DOISPONTOS tipo proc_or_func2
        ;

proc_or_func1    : ID ABREPAR parametros FECHAPAR
        | ID ABREPAR FECHAPAR
        | ID
        ;

parametros    : VAR ID DOISPONTOS tipo
        | parametros PONTOEVIRGULA VAR ID DOISPONTOS tipo
        | ID DOISPONTOS tipo
        | parametros PONTOEVIRGULA ID DOISPONTOS tipo
        ;

proc_or_func2    : PONTOEVIRGULA subprogram_const
        ;

subprogram_const : const_decl PONTOEVIRGULA subprogram_var
         | subprogram_var
         ;

subprogram_var  : var_decl PONTOEVIRGULA bloco
          | bloco
        ;
        
aspect_decl :
    ASPECT ID bloco | aspect_decl PONTOEVIRGULA ID bloco;

before_after : 
    BEFORE ID DOISPONTOS ID | AFTER ID DOISPONTOS ID ;

before_after_list :
    before_after | before_after_list PONTOEVIRGULA before_after ; 


type_st    : RECORD record_fields
    | POINTER pointer_tipo
    | tipo
    ;

record_fields     : campo_decl PONTOEVIRGULA FIM
        ;

campo_decl    : campo_decl PONTOEVIRGULA ID DOISPONTOS type_st
        | ID DOISPONTOS type_st
        ;
    
pointer_tipo    : REAL
        | INTEGER
        | CHAR_TYPE
        | BOOLEAN
        | STRING_TYPE
        | ID
        ;
    
tipo    : tipo2 REAL
    | tipo2 INTEGER
    | tipo2 CHAR_TYPE
    | tipo2 BOOLEAN
    | tipo2 STRING_TYPE
    | tipo2 ID 
    ;

tipo2    : tipo2 ARRAY array_range OF
    |
    ;

array_range    : array_range ABRECOL NUMERO RANGE NUMERO FECHACOL
        | ABRECOL NUMERO RANGE NUMERO FECHACOL
        ;        

valor    : NUMERO 
    | FLOAT    
    | STRING_TERM 
    | CHAR_TERM 
    | TRUE 
    | FALSE 
    ;

bloco    : INICIO sec_instrucao FIM
    ;
    
sec_instrucao    : sec_instrucao PONTOEVIRGULA instrucao
        | instrucao 
        ;

instrucao    : if
        | while 
        | for
        | repeat
        | case
        | ID ABREPAR parametros_entrada FECHAPAR
        | bloco
        |
        | ID ABREPAR FECHAPAR
        | atribuicao
        ;

if    : IF expressao THEN instrucao FIM
    | IF expressao THEN instrucao ELSE instrucao FIM
    ;
    
while    : WHILE expressao DO instrucao
    ;
    
for    : FOR ID ATRIBUICAO expressao TO expressao DO instrucao
    | FOR ID ATRIBUICAO expressao DOWNTO expressao DO instrucao
    ;

repeat    : REPEAT instrucao UNTIL expressao
    ;

case    : CASE expressao OF case_inst FIM PONTOEVIRGULA
    | CASE expressao OF case_inst ELSE instrucao FIM PONTOEVIRGULA
    ;

case_inst    : case_inst valor DOISPONTOS instrucao PONTOEVIRGULA
        | valor DOISPONTOS instrucao PONTOEVIRGULA
        ;

parametros_entrada    : parametros_entrada PONTOEVIRGULA expressao
            | expressao
            ;

atribuicao    : elem_variavel ATRIBUICAO expressao
        ;

simu    : tios
    | colEx
    | elem_var
    ;

tios    : tios POINTER
    | POINTER
    ;

colEx    : colEx ABRECOL expressao FECHACOL
    | ABRECOL expressao FECHACOL
    ;
    
elem_var    : ID simu
        ;

elem_variavel    : ID
        | ID ABREPAR FECHAPAR
        | ID ABREPAR parametros_entrada FECHAPAR
        | ID simu
        | ID ABREPAR FECHAPAR simu
        | ID ABREPAR parametros_entrada FECHAPAR simu
        ;
        
op_bin    : MAIS
    | MENOS
    | OP_ARITMETICO
    | OP_LOGICO
    | RELOP
    ;     

expressao     : MENOS ABREPAR expressao FECHAPAR
        | NAO ABREPAR expressao FECHAPAR
        | ABREPAR expressao FECHAPAR
        | MENOS valor
        | NAO valor
        | valor
        | MENOS elem_variavel
        | NAO elem_variavel
        | elem_variavel
        | MENOS ABREPAR expressao FECHAPAR op_bin expressao
        | NAO ABREPAR expressao FECHAPAR op_bin expressao
        | ABREPAR expressao FECHAPAR op_bin expressao
        | MENOS valor op_bin expressao
        | NAO valor op_bin expressao
        | valor op_bin expressao
        | MENOS elem_variavel op_bin expressao
        | NAO elem_variavel op_bin expressao
        | elem_variavel op_bin expressao
        ;

%%

#include "lex.yy.c"


int main(void) {
    
    inicializarTradutor();
    //    #if YYDEBUG
    //    yydebug = 1;
        //    #endif
    yyparse();
    //printOnFile();
    return 0;
}

//int main() {
//    yyparse();
//    return 0;
//
//}


